"""认证模块"""
from datetime import datetime, timedelta
from typing import Optional
from fastapi import Depends, HTTPException, Security
from fastapi.security import OAuth2PasswordBearer, APIKeyHeader
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
from starlette.status import HTTP_401_UNAUTHORIZED
from .config import AUTH_CONFIG, USERS_DB

# 密码上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2 scheme
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# API密钥header
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)

class Token(BaseModel):
    """Token模型"""
    access_token: str
    token_type: str

class TokenData(BaseModel):
    """Token数据模型"""
    username: Optional[str] = None

class User(BaseModel):
    """用户模型"""
    username: str
    disabled: Optional[bool] = None

class UserInDB(User):
    """数据库中的用户模型"""
    hashed_password: str

def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    """获取密码哈希"""
    return pwd_context.hash(password)

def get_user(username: str) -> Optional[UserInDB]:
    """获取用户"""
    if username in USERS_DB:
        user_dict = USERS_DB[username]
        return UserInDB(**user_dict)
    return None

def authenticate_user(username: str, password: str) -> Optional[UserInDB]:
    """认证用户"""
    user = get_user(username)
    if not user:
        return None
    if not verify_password(password, user.hashed_password):
        return None
    return user

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """创建访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(
        to_encode, 
        AUTH_CONFIG["SECRET_KEY"], 
        algorithm=AUTH_CONFIG["ALGORITHM"]
    )
    return encoded_jwt

async def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
    """获取当前用户"""
    credentials_exception = HTTPException(
        status_code=HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(
            token, 
            AUTH_CONFIG["SECRET_KEY"], 
            algorithms=[AUTH_CONFIG["ALGORITHM"]]
        )
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = TokenData(username=username)
    except JWTError:
        raise credentials_exception
    user = get_user(username=token_data.username)
    if user is None:
        raise credentials_exception
    return user

async def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
    """获取当前活跃用户"""
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

async def verify_api_key(api_key: str = Security(api_key_header)) -> Optional[str]:
    """验证API密钥"""
    if api_key in AUTH_CONFIG["API_KEYS"]:
        return AUTH_CONFIG["API_KEYS"][api_key]
    return None

async def get_auth_user(
    api_key: str = Security(api_key_header),
    token: str = Depends(oauth2_scheme)
) -> User:
    """获取认证用户(支持API密钥或JWT认证)"""
    # 首先尝试API密钥认证
    if api_key:
        username = await verify_api_key(api_key)
        if username:
            user = get_user(username)
            if user:
                return user
    
    # 如果API密钥认证失败，尝试JWT认证
    return await get_current_active_user(token) 